package org.coody.framework.minicat.entity;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.coody.framework.minicat.adapt.ParamentAdapt;
import org.coody.framework.minicat.config.MiniCatConfig;
import org.coody.framework.minicat.container.SessionContainer;
import org.coody.framework.minicat.util.ByteUtils;
import org.coody.framework.minicat.util.GZIPUtils;
import org.coody.framework.minicat.util.StringUtil;

public class HttpServletRequest {

	private String method="GET";

	private String protocol;

	private String requestURI;

	private String requestURL;

	private String relativeURI;

	private Map<String, String> header;

	private InputStream inputStream;

	private String sessionId;

	private boolean isGzip = false;

	private boolean isSessionCread = false;

	private String scheme = (MiniCatConfig.HTTP_PORT == 443 ? "https" : "http");

	private String basePath;

	private Map<String, List<Object>> params;

	private String queryString = "";

	private Integer contextLength = 0;

	
	
	public MultipartFile getFile(String paramName){
		if (params == null) {
			initParams();
		}
		List<Object> paramValues = params.get(paramName);
		if (StringUtil.isNullOrEmpty(paramValues)) {
			return null;
		}
		Object value= paramValues.get(0);
		if(!MultipartFile.class.isAssignableFrom(value.getClass())){
			return null;
		}
		return (MultipartFile) value;
	}
	public String getParament(String paramName) {
		if (params == null) {
			initParams();
		}
		List<Object> paramValues = params.get(paramName);
		if (StringUtil.isNullOrEmpty(paramValues)) {
			return null;
		}
		Object value=paramValues.get(0);
		if(MultipartFile.class.isAssignableFrom(value.getClass())){
			try {
				return new String(((MultipartFile)value).getFileContext(),MiniCatConfig.ENCODE);
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
				return null;
			}
		}
		return value.toString();
	}

	
	
	public Map<String, List<Object>> getParams() {
		if(StringUtil.isNullOrEmpty(params)) {
			initParams();
		}
		return params;
	}
	public void setParams(Map<String, List<Object>> params) {
		this.params = params;
	}
	private void initParams(){
		params = ParamentAdapt.buildGeneralParams(queryString);
		if (header.containsKey("Content-Type") && header.get("Content-Type").contains("multipart/form-data")) {
			String line = header.get("Content-Type");
			String[] dabbles = line.split(";");
			String boundary = "";
			for (String dabble : dabbles) {
				int index = dabble.indexOf("=");
				if (index < 1 || index > dabble.length()) {
					continue;
				}
				String name = dabble.substring(0, dabble.indexOf("=")).trim();
				String value = dabble.substring(dabble.indexOf("=") + 1);
				if (name.equals("boundary")) {
					boundary = value;
				}
			}
			byte[] data = ByteUtils.getBytes(inputStream,contextLength);
			Map<String, List<Object>> paramMap = ParamentAdapt.buildMultipartParams(data, boundary);
			params = mergeParaMap(params, paramMap);
		} else {
			String postContext = getPostContext();
			if (!StringUtil.isNullOrEmpty(postContext)) {
				Map<String, List<Object>> paramMap = ParamentAdapt.buildGeneralParams(postContext);
				params = mergeParaMap(params, paramMap);
			}
		}
	}
	private Map<String, List<Object>> mergeParaMap(Map<String, List<Object>> paraMap1,
			Map<String, List<Object>> paraMap2) {

		if (StringUtil.isNullOrEmpty(paraMap1)) {
			return paraMap2;
		}
		if (StringUtil.isNullOrEmpty(paraMap2)) {
			return paraMap1;
		}
		for (String key : paraMap1.keySet()) {
			if (!paraMap2.containsKey(key)) {
				paraMap2.put(key, paraMap1.get(key));
				continue;
			}
			paraMap2.get(key).addAll(paraMap1.get(key));
		}
		return paraMap2;
	}

	public String getPostContext() {
		try {
			byte[] data = ByteUtils.getBytes(inputStream,contextLength);
			if (data == null) {
				return null;
			}
			if (isGzip) {
				data = GZIPUtils.uncompress(data);
			}
			return new String(data, MiniCatConfig.ENCODE);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public HttpSession getSession() {
		sessionId = getSessionId();
		HttpSession session = SessionContainer.getSession(sessionId);
		if (!StringUtil.isNullOrEmpty(session)) {
			return session;
		}
		isSessionCread = true;
		sessionId = SessionContainer.createSessionId();
		session = SessionContainer.initSession(sessionId);
		return session;
	}

	public String getSessionId() {
		if (!StringUtil.isNullOrEmpty(sessionId)) {
			return sessionId;
		}
		if (StringUtil.isNullOrEmpty(header)) {
			return null;
		}
		String cookie = header.get("Cookie");
		if (StringUtil.isNullOrEmpty(cookie)) {
			return null;
		}
		if (!cookie.contains(MiniCatConfig.SESSION_ID_FIELD_NAME)) {
			return null;
		}
		String[] cookies = cookie.split(";");
		for (String line : cookies) {
			if (!line.contains(MiniCatConfig.SESSION_ID_FIELD_NAME)) {
				continue;
			}
			int index = line.indexOf("=");
			sessionId = line.substring(index + 1).trim();
			return sessionId;
		}
		return null;
	}

	public HttpServletRequest() throws IOException {
	}

	public String getBasePath() {
		return basePath;
	}

	public void setBasePath(String basePath) {
		this.basePath = basePath;
	}

	public String getScheme() {
		return scheme;
	}

	public String getQueryString() {
		return queryString;
	}

	public void setQueryString(String queryString) {
		this.queryString = queryString;
	}

	public Integer getContextLength() {
		return contextLength;
	}

	public void setContextLength(Integer contextLength) {
		this.contextLength = contextLength;
	}

	public void setScheme(String scheme) {
		this.scheme = scheme;
	}

	public boolean isSessionCread() {
		return isSessionCread;
	}

	public void setSessionCread(boolean isSessionCread) {
		this.isSessionCread = isSessionCread;
	}

	public boolean isGzip() {
		return isGzip;
	}

	public void setGzip(boolean isGzip) {
		this.isGzip = isGzip;
	}

	public void setSessionId(String sessionId) {
		this.sessionId = sessionId;
	}

	public String getProtocol() {
		return protocol;
	}

	public void setProtocol(String protocol) {
		this.protocol = protocol;
	}

	public String getMethod() {
		return method;
	}

	public void setMethod(String method) {
		this.method = method;
	}

	public String getRequestURI() {
		return requestURI;
	}

	public void setRequestURI(String requestURI) {
		if(requestURI==null) {
			requestURI="";
		}
		requestURI=requestURI.replace("\\", "/");
		while(requestURI.contains("//")) {
			requestURI=requestURI.replace("//", "/");
		}
		if(requestURI.trim().equals("/")||requestURI.trim().equals("")) {
			requestURI=MiniCatConfig.WELCOME_PATH;
		}
		this.requestURI = requestURI;
	}

	public String getRequestURL() {
		return requestURL;
	}

	public void setRequestURL(String requestURL) {
		this.requestURL = requestURL;
	}

	public String getRelativeURI() {
		return relativeURI;
	}

	public void setRelativeURI(String relativeURI) {
		this.relativeURI = relativeURI;
	}

	public Map<String, String> getHeader() {
		return header;
	}

	public void setHeader(String name,String value) {
		if(header==null){
			header=new HashMap<String, String>();
		}
		header.put(name, value);
	}

	public InputStream getInputStream() {
		return inputStream;
	}

	public void setInputStream(InputStream inputStream) {
		this.inputStream = inputStream;
	}

}
